﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace PNGInfo.Framework
{
    public class PNGTag
    {
        public string FullTagData { get; set; }
        public string RelativePath { get; set; }
        public Size Size { get; set; }

        [XmlIgnore]
        public string FileName { get; set; }

        [XmlIgnore]
        public string FullName { get; set; }

        private string tagData = null;
        [XmlIgnore]
        public string TagData
        {
            get
            {
                return tagData;
            }
            set
            {
                tagData = value;
            }
        }

        private string modelHash = null;
        [XmlIgnore]
        public string ModelHash
        {
            get
            {
                return modelHash;
            }
        }

        private string modelName = null;
        [XmlIgnore]
        public string ModelName
        {
            get
            {
                return modelName;
            }
            set
            {
                modelName = value;
            }
        }

        public PNGTag(string fileName, string root)
        {
            FullName = fileName;
            FileName = Path.GetFileName(fileName);
            if(root != null)
                RelativePath = FullName.Substring(FullName.IndexOf(root) + root.Length + 1);

            TagLib.File file = TagLib.File.Create(fileName, TagLib.ReadStyle.Average);

            if (file.Properties != null)
                Size = new Size(file.Properties.PhotoWidth, file.Properties.PhotoHeight);

            if (file.GetTag(TagLib.TagTypes.Png, false) is TagLib.Png.PngTag tag)
            {
                FullTagData = tag.GetKeyword("parameters");
                if (FullTagData != null)
                {
                    StringBuilder sb = new StringBuilder(FullTagData.Length);
                    foreach (char c in FullTagData)
                    {
                        if (c == '\0')
                            continue;

                        if (c == '\n')
                            sb.Append(Environment.NewLine);
                        else
                            sb.Append(c);

                    }
                    FullTagData = sb.ToString();
                    PopulateTagData();
                }
            }
        }

        private PNGTag() { }

        public void Populate(string root)
        {
            FullName = Path.Combine(root, RelativePath);
            FileName = Path.GetFileName(FullName);
            PopulateTagData();
        }

        private static readonly char[] modelHashMatch = new char[] { 'M', 'o', 'd', 'e', 'l', ' ', 'h', 'a', 's', 'h', ':', ' ' };
        private static readonly char[] modelNameMatch = new char[] { 'M', 'o', 'd', 'e', 'l', ':', ' ' };
        private void PopulateTagData()
        {
            int modelHashFoundIndex = 0;
            bool matchingHash = false;
            bool readingHash = false;
            bool loadedHash = false;

            int modelNameFoundIndex = 0;
            bool matchingModel = false;
            bool readingModel = false;
            bool loadedModel = false;

            StringBuilder sb = new StringBuilder(FullTagData.Length);
            StringBuilder hash = new StringBuilder();
            StringBuilder model = new StringBuilder();
            foreach (char c in FullTagData)
            {
                if (c == '\r')
                    continue;

                if (c == '\n')
                    sb.Append(' ');
                else
                {
                    sb.Append(c);

                    if (!loadedHash)
                    {
                        if (!readingHash)
                        {
                            if (c == modelHashMatch[modelHashFoundIndex])
                            {
                                matchingHash = true;
                                modelHashFoundIndex++;
                                if (modelHashFoundIndex == 12)
                                {
                                    readingHash = true;
                                }
                            }
                            else if (matchingHash && modelHashFoundIndex > 0)
                            {
                                matchingHash = false;
                                modelHashFoundIndex = 0;
                            }
                        }
                        else
                        {
                            if (c == ',')
                            {
                                readingHash = false;
                                loadedHash = true;
                            }
                            else
                            {
                                hash.Append(c);
                            }
                        }
                    }

                    if (!loadedModel)
                    {
                        if (!readingModel)
                        {
                            if (c == modelNameMatch[modelNameFoundIndex])
                            {
                                matchingModel = true;
                                modelNameFoundIndex++;
                                if (modelNameFoundIndex == 7)
                                {
                                    readingModel = true;
                                }
                            }
                            else if (matchingModel && modelNameFoundIndex > 0)
                            {
                                matchingModel = false;
                                modelNameFoundIndex = 0;
                            }
                        }
                        else
                        {
                            if (c == ',')
                            {
                                readingModel = false;
                                loadedModel = true;
                            }
                            else
                            {
                                model.Append(c);
                            }
                        }
                    }
                }
            }
            tagData = sb.ToString();

            if(model.Length > 0)
            {
                ModelName = model.ToString();
            }

            if(hash.Length > 0)
            {
                modelHash = hash.ToString();

                if (ModelName == null && ModelHasher.ModelHasherState.State.TryGetModelHashByHash(modelHash, out ModelHasher.Framework.ModelHash mHash))
                {
                    modelName = mHash.Name;
                }
            }
        }
    }
}
